package ymy;

import ymy.common.*;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;

public abstract class BaseSimulator {
    private static Random random = new Random(System.currentTimeMillis());

    protected Environment environment;
    protected Map<Integer, Vehicle> parkVehicleMap;
    protected Map<Integer, Vehicle> moveVehicleMap;
    protected Map<Integer, VirtualLink> virtualLinkMap;

    protected List<StageResult> stageResults;

    protected volatile int vid = 0;
    protected volatile boolean initf = false;

    public BaseSimulator(Environment env) {
        this.environment = env;
        this.parkVehicleMap = new HashMap<>();
        this.moveVehicleMap = new HashMap<>();
        this.virtualLinkMap = new HashMap<>();
        this.stageResults = new ArrayList<>();
    }

    public void clearStage() {
        this.vid = 0;
        this.parkVehicleMap.clear();
        this.moveVehicleMap.clear();
        this.virtualLinkMap.clear();
        this.initf = false;
    }

    public void initSimulation(boolean ov) {
        if (ov) {
            this.initParkVehiclesOV();
            this.initMoveVehiclesOV();
        } else {
            this.initParkVehicles();
            this.initMoveVehicles();
        }
        this.initf = true;
    }

    public abstract void vehicleMoveAction(Vehicle v, double duration);

    public abstract void initMoveVehicles();

    public abstract void initParkVehicles();

    public abstract void initMoveVehiclesOV();

    public abstract void initParkVehiclesOV();

    // 工具函数，获取移动车辆数量
    public int getMoveVehiclesCount() {
        return this.moveVehicleMap.size();
    }

    // 工具函数，获取停驻车辆数量
    public int getParkVehiclesCount() {
        return this.parkVehicleMap.size();
    }

    // 工具函数，根据起始车辆信息获取对应的虚拟链路信息
    public VirtualLink getVirtualLink(Vehicle sv, Vehicle tv) {
        if (sv.getId() == tv.getId())
            return null;

        int key = sv.getId() * 10000 + tv.getId();
        if (this.virtualLinkMap.containsKey(key)) {
            return this.virtualLinkMap.get(key);
        }

        VirtualLink vl = new VirtualLink();
        vl.setBegv(sv);
        vl.setEndv(tv);

        if (tv.isParked()) {
            vl.setTransDelay(GeneralConfig.VEHICLE_PARK_PTIME);
        }
        if (!tv.isParked()) {
            vl.setTransDelay(GeneralConfig.VEHICLE_MOVE_PTIME);
        }

        this.virtualLinkMap.put(key, vl);

        return vl;
    }

    // 工具函数，根据起始车辆的速度及距离得到对应的链路质量，仅用于仿真
    public void predictVirtualLinkQuality(VirtualLink vl) {
        /*
         距离与信号质量的基本关系如下图所示：
            ^
        1.00|-------------- 0.95
            |              \
         0.8|               \ 0.85
            |                ---- 0.70
         0.6|                    \
            |                     \ 0.50
            |                      ---- 0.30
         0.1|                          \
            |                           \ 0.10
          0 ~----------------------------------->
            0            0.5 0.6 0.7 0.8 0.9 1.0
           基本关系如下：
           <距离-信号质量>（距离为相较于最长通信距离的比例而言）
           (0.00, 0.50) -- 1.00
           (0.50, 0.60) -- 0.90
           (0.60, 0.70) -- 0.80
           (0.70, 0.80) -- 0.70
           (0.80, 0.90) -- 0.60
           (0.90, 1.00) -- 0.40
           同时，对于车辆来说，通信双方有如下说法：
           1. 两者一为移动，则信号质量*0.80
           2. 两者均为停驻，则信号质量*1.00
           3. 两者均为移动，则信号质量*0.60
           同时，若通信双方被遮挡，则信号质量*0.01
         */
        double quality = 0.0;
        double distance = vl.getTransDistance();
        double protion = distance / GeneralConfig.FAILURE_DISTANCE;

        if (protion >= 0.0 && protion < 0.50) {
            quality = 1.00;
        } else if (protion >= 0.50 && protion < 0.60) {
            quality = 0.90;
        } else if (protion >= 0.60 && protion < 0.70) {
            quality = 0.80;
        } else if (protion >= 0.70 && protion < 0.80) {
            quality = 0.70;
        } else if (protion >= 0.80 && protion < 0.90) {
            quality = 0.60;
        } else if (protion >= 0.90 && protion < 1.00) {
            quality = 0.40;
        } else {
            quality = 0.0;
        }

        Vehicle begv = vl.getBegv();
        Vehicle endv = vl.getEndv();
        if (begv.isParked() && endv.isParked()) {
            quality *= 1.00;
        } else if (!begv.isParked() && !endv.isParked()) {
            quality *= 0.60;
        } else {
            quality *= 0.80;
        }

        boolean isSheltered = Utility.linkSheltered(begv.getPosition(), endv.getPosition(), this.environment.getBuildingList());
        if (isSheltered) {
            quality *= 0.01;
        }

        vl.setSheltered(isSheltered);
        vl.setLinkQuality(quality);
        vl.setPacketLoss(1.0 - quality);

        if (GeneralConfig.LINK_SELECT_TYPE == GeneralConfig.FD) {
            vl.setSelectWeight(distance);
        } else if (GeneralConfig.LINK_SELECT_TYPE == GeneralConfig.LD) {
            vl.setSelectWeight(quality * distance);
        } else if (GeneralConfig.LINK_SELECT_TYPE == GeneralConfig.QP) {
            vl.setSelectWeight(quality);
        }
    }

    public void updateVehiclesStatus(List<Vehicle> vehicles, double currTime, double duration) {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]更新所有车辆的状态信息...");
        }
        // 启动和处理运行车辆的状态迁移过程
        for (Vehicle v : vehicles) {
            v.clearVehicleStage();

            if (v.isParked()) {
                continue;
            }

            if (currTime >= v.getMoment()) {
                v.setRunning(true);
            }

            // 移动车辆根据移动时长进行移动
            if (v.isRunning()) {
                this.vehicleMoveAction(v, duration);
            }
        }

        // 更新所有车辆的相邻车辆信息
        int size = vehicles.size();
        for (int i = 0; i < size; i++) {
            Vehicle vi = vehicles.get(i);

            // 如果车辆i没有处于运行状态，则继续下一次循环
            if (!vi.isRunning()) {
                continue;
            }

            for (int j = 0; j < size; j++) {
                Vehicle vj = vehicles.get(j);

                // 忽略回环情况
                if (i == j) {
                    continue;
                }

                // 如果车辆j没有处于运行状态，则继续下一次循环
                if (!vj.isRunning()) {
                    continue;
                }

                // 如果车辆i和车辆j都是停驻车辆且位于同一区域，则认为i和j无邻接关系
                if (vi.isParked() && vj.isParked() && vi.getArea().equals(vj.getArea())) {
                    continue;
                }

                // 如果车辆i和车辆j相距太远（超过某一阈值），则认为i和j无邻接关系
                double dist = Utility.distance(vi.getPosition(), vj.getPosition());
                if (dist >= GeneralConfig.FAILURE_DISTANCE) {
                    continue;
                }

                // 获取虚拟链路信息，设置通信距离，然后根据车辆i与车辆j的关系（距离+速度），得出两者之间的数据包传输成功率并更新
                VirtualLink vl = this.getVirtualLink(vi, vj);
                vl.setTransDistance(dist);
                this.predictVirtualLinkQuality(vl);

                // 如果链路质量小于某个阈值，则认为链路断开，不加入车辆i的邻接表中
                if (vl.getLinkQuality() > GeneralConfig.LINK_QUALITY_THRESHOLD) {
                    vi.addConnectedVirtualLink(vl);
                }

                if (GeneralConfig.DEBUG_UPDATE) {
                    System.out.println("UPDATED = (" + vi.getId() + ", " + vj.getId() + ") = " + vl.getLinkQuality());
                }
            }
        }

        if (GeneralConfig.DEBUG_CONNECTED) {
            for (Vehicle v : vehicles) {
                System.out.println("NODE X = " + v.getId());
                System.out.println("NODE V = " + v.getPosition());
                System.out.println("CONNECTED_NODES = " + v.getConnectedVirtualLinks().size());
                for (VirtualLink vl : v.getConnectedVirtualLinks()) {
                    System.out.println();
                    System.out.println(vl.getEndv().isParked());
                    System.out.println("StartNode = " + vl.getBegv().getId());
                    System.out.println("NodePos = " + vl.getBegv().getPosition());
                    System.out.println("NodeHost = " + vl.getEndv().getId());
                    System.out.println("NodePos = " + vl.getEndv().getPosition());
                    System.out.printf("Distance = %.3f\n", Utility.distance(vl.getBegv().getPosition(), vl.getEndv().getPosition()));
                }
                System.out.println("-------------------");
            }
        }
    }

    public void broadcastHelloPacket(List<Vehicle> vehicles, int helloCount) {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]所有车辆广播Hello报文...");
        }
        for (Vehicle bv : vehicles) {
            for (VirtualLink vl : bv.getConnectedVirtualLinks()) {
                vl.setHelloPktCntMove(0);
                vl.setHelloPktCntPark(0);
                Vehicle ev = vl.getEndv();
                if (ev.fetchVehicleConnectedVirtualLink(bv) != null) {
                    for (int i = 0; i < helloCount; i++) {
                        if (!vl.isPacketSuccess()) {
                            continue;
                        }

                        if (bv.isParked()) {
                            vl.incrementHelloPktCntPark();
                        } else {
                            vl.incrementHelloPktCntMove();
                        }
                    }
                }
            }
        }
    }

    public void calculateVirtualLinkQuality(VirtualLink vl, int helloCount) {
        // 分别计算从停驻车辆和移动车辆的接收包率
        double lq_park = vl.getHelloPktCntPark() / helloCount;
        double lq_move = vl.getHelloPktCntMove() / helloCount;

        // 传输数据包优先使用移动车辆（因此只考虑从移动车辆传输来的信道质量）
        if (GeneralConfig.SIMULATION_TYPE == GeneralConfig.MOVE_ONLY) {
            vl.setLinkQuality(lq_move);
        }

        // 传输数据包综合使用停驻或移动车辆（比重考虑）
        if (GeneralConfig.SIMULATION_TYPE == GeneralConfig.PARK_MOVE) {
            vl.setLinkQuality(lq_park + lq_park);
        }

        // 设置选择比重
        vl.setSelectWeight(vl.getTransDistance() * vl.getLinkQuality());
    }

    public void relaySelection(List<Vehicle> vehicles, int helloCount) {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]所有车辆进行中继选择过程...");
        }
        for (Vehicle bv : vehicles) {
            double sumDist = 0.0;
            double averDist = 0.0;

            for (VirtualLink vl : bv.getConnectedVirtualLinks()) {
                sumDist += vl.getTransDistance();
                //this.calculateVirtualLinkQuality(vl, helloCount);

                // 记录历史记录
                vl.appendLinkQualityHistory(vl.getLinkQuality());
            }

            // 计算平均通信距离
            int size = bv.getConnectedVirtualLinks().size();
            if (size > 0) {
                averDist = sumDist / size;
            }

            // 对虚拟链路进行降序排序
            Collections.sort(bv.getConnectedVirtualLinks());

            int cnt = 0;
            for (VirtualLink vl : bv.getConnectedVirtualLinks()) {
                if (vl.getTransDistance() >= averDist) {
                    continue;
                }

                bv.addSelectedVirtualLink(vl);

                cnt++;
                if (cnt >= GeneralConfig.SELECT_COUNT) {
                    break;
                }
            }

            if (GeneralConfig.DEBUG_RELAY) {
                System.out.println("Target Vehicle ID = " + bv.getId());
                System.out.println("Summary Distance = " + sumDist);
                System.out.println("Average Distance = " + averDist);
                System.out.println("Connected Virtual Links = " + size);
                System.out.println("Selected Virtual Links = " + bv.getSelectedVirtualLinks().size());
                System.out.println("Selected Virtual Links Information => {");
                for (VirtualLink vl : bv.getSelectedVirtualLinks()) {
                    System.out.println(vl);
                    System.out.println("VL NEXT = " + bv.isParked());
                    System.out.println("--------------------");
                }
                System.out.println("Connected Virtual Links Information => {");
                for (VirtualLink vl : bv.getConnectedVirtualLinks()) {
                    System.out.println(vl);
                    System.out.println("VL NEXT = " + bv.isParked());
                    System.out.println("---------------------");
                }
                System.out.println("}");
            }
        }
    }

    private void handlePathResult(Map<Vehicle, PathResult> prMap, PathResult pr) {
        Vehicle b = pr.getBegv();
        Vehicle e = pr.getEndv();

        pr.setDist(Utility.distance(b.getPosition(), e.getPosition()));

        List<VirtualLink> vllist = new ArrayList<>();
        List<Vehicle> vclist = new ArrayList<>();

        // 获取对应的路径信息，包括链路+节点列表
        vclist.add(e);
        Vehicle v = pr.getPrev();
        Vehicle ev = e;
        Vehicle sv = v;
        while (v != b) {
            PathResult tpr = prMap.get(v);
            vclist.add(v);

            VirtualLink vl = getVirtualLink(sv, ev);
            vllist.add(vl);

            ev = v;
            v = tpr.getPrev();
            sv = v;
        }
        vclist.add(b);
        VirtualLink vl = getVirtualLink(sv, ev);
        vllist.add(vl);

        pr.setPathNodes(vclist);
        pr.setPathLinks(vllist);
    }

    public StageResult pathProcess(List<Vehicle> vehicles) {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]路径计算处理过程...");
        }
        double totalADelay = 0.0;
        double totalAQuality = 0.0;
        double totalAHops = 0.0;
        double totalADist = 0.0;

        double totalDelay = 0.0;
        double totalQuality = 0.0;
        double totalHops = 0.0;
        double totalDist = 0.0;

        StageResult sr = new StageResult();

        Map<Vehicle, Map<Vehicle, PathResult>> pathResultCollectionMap = new HashMap<>();
        for (Vehicle bv : vehicles) {
            if (bv.isParked()) {
                continue;
            }

            Map<Vehicle, PathResult> prMap = new HashMap<>();
            Set<Vehicle> visited = new HashSet<>();
            double waitdelay = 0.0;

            for (Vehicle v : vehicles) {
                v.algoValue = GeneralConfig.DOUBLE_MAX_VALUE;
                prMap.put(v, new PathResult(bv, v));
            }

            Queue<Vehicle> queue = new PriorityQueue<>();

            bv.algoValue = 0.0;
            queue.offer(bv);

            PathResult bpr = prMap.get(bv);
            bpr.setDelay(0.0);
            bpr.setHops(0.0);
            bpr.setQuality(1.0);

            while (!queue.isEmpty()) {
                Vehicle v = queue.poll();
                visited.add(v);

                PathResult currpr = prMap.get(v);
                int wid = 0;
                for (VirtualLink vl : v.getSelectedVirtualLinks()) {
                    Vehicle ev = vl.getEndv();
                    if (visited.contains(ev)) {
                        continue;
                    }

                    PathResult pr = prMap.get(ev);
                    waitdelay = vl.getTransDelay();
                    if (ev.isParked())
                        waitdelay += random.nextInt((int)GeneralConfig.VEHICLE_WAIT_DELTA);
                    else
                        waitdelay += wid * GeneralConfig.VEHICLE_WAIT_DELTA;
                    if (ev.algoValue > v.algoValue + waitdelay) {
                        pr.setQuality(currpr.getQuality() * vl.getLinkQuality());
                        pr.setDelay(currpr.getDelay() + waitdelay);
                        pr.setHops(currpr.getHops() + 1.0);
                        pr.setPrev(v);

                        if (queue.contains(ev)) {
                            queue.remove(ev);
                        }
                        ev.algoValue = v.algoValue + waitdelay;
                        queue.offer(ev);
                    }
                    wid++;
                }

                for (VirtualLink vl : v.getConnectedVirtualLinks()) {
                    if (v.getSelectedVirtualLinks().contains(vl)) {
                        continue;
                    }

                    Vehicle ev = vl.getEndv();
                    PathResult pr = prMap.get(ev);
                    if (pr.getDelay() >= GeneralConfig.DOUBLE_MAX_VALUE) {
                        pr.setQuality(currpr.getQuality() * vl.getLinkQuality());
                        pr.setHops(currpr.getHops() + 1.0);
                        pr.setDelay(currpr.getDelay() + vl.getTransDelay());
                        pr.setPrev(v);
                    }
                }
            }

            pathResultCollectionMap.put(bv, prMap);
            for (PathResult p : prMap.values()) {
                if (p.getEndv().isParked()) {
                    continue;
                }

                if (p.getBegv().equals(p.getEndv())) {
                    continue;
                }

                Vehicle b = p.getBegv();
                Vehicle e = p.getEndv();
                p.setDist(Utility.distance(b.getPosition(), e.getPosition()));

                if (p.getHops() == GeneralConfig.DOUBLE_MAX_VALUE) {
                    p.setDelay(GeneralConfig.UNDELAY);
                    p.setQuality(GeneralConfig.UNLQ);
                    p.setHops(GeneralConfig.UNHOP);
                    p.setConnected(false);
                } else {
                    this.handlePathResult(prMap, p);
                    p.setConnected(true);

                    totalDelay += p.getDelay();
                    totalQuality += p.getQuality();
                    totalHops += p.getHops();
                    totalDist += p.getDist();

                    sr.successCount++;
                }

                sr.addPathResult(p);
                sr.totalCount++;

                totalADelay += p.getDelay();
                totalAQuality += p.getQuality();
                totalAHops += p.getHops();
                totalADist += p.getDist();

                if (GeneralConfig.DEBUG_SPFA) {
                    System.out.println("ALGORITHM RESULT: {");
                    System.out.println("  Beg ID = " + b.getId());
                    System.out.println("  End ID = " + e.getId());
                    System.out.printf("  FROM %d TO %d: \n", b.getId(), e.getId());
                    System.out.println("  Beg Vehicle = " + b.getPosition());
                    System.out.println("  End Vehicle = " + e.getPosition());
                    System.out.printf("  Distance = %.4f\n", Utility.distance(b.getPosition(), e.getPosition()));
                    System.out.printf("  Quality = %.4f\n", p.getQuality());
                    System.out.printf("  Delay = %.4f\n", p.getDelay());
                    System.out.println("  HopCount = " + p.getHops());
                    System.out.println("\n  Path Nodes = ");
                    for (Vehicle vt : p.getPathNodes()) {
                        System.out.print("=>[[" + vt.getId() + vt.getPosition() + "<" + vt.isParked() + ">" + "]]");
                    }
                    System.out.println("\n  Path Links = ");
                    for (VirtualLink l : p.getPathLinks()) {
                        System.out.println("====");
                        System.out.println(l);
                    }
                    System.out.println("}");
                    System.out.println("-------------------------------------------------------------");
                }
            }
        }

        sr.setAdelay(totalADelay / sr.totalCount);
        sr.setAquality(totalAQuality / sr.totalCount);
        sr.setAhops(totalAHops / sr.totalCount);
        sr.setAdist(totalADist / sr.totalCount);

        sr.setDelay(totalDelay / sr.successCount);
        sr.setQuality(totalQuality / sr.successCount);
        sr.setHops(totalHops / sr.successCount);
        sr.setDist(totalDist / sr.successCount);

        return sr;
    }

    // 根据仿真类型进行特定的仿真过程处理
    public StageResult doSimulation(List<Vehicle> vehicles, double period, int helloCount, int sampleCount, int processCount) {
        double currTime = 0.0;
        double sumDelay = 0.0;
        double sumQuality = 0.0;
        double sumHops = 0.0;
        double sumDist = 0.0;

        double sumADelay = 0.0;
        double sumAQuality = 0.0;
        double sumAHops = 0.0;
        double sumADist = 0.0;

        int sumCount = 0;
        int sumSuccess = 0;
        StageResult stageResult = new StageResult();

        for (int i = 0; i < processCount; i++) {
            for (Vehicle v : vehicles) {
                v.clearVehicleStage();
            }

            if (GeneralConfig.DEBUG_INFO) {
                System.out.println("====================================");
                System.out.println("[INFO]>>>第" + (i + 1) + "轮<共" + processCount + "轮>仿真周期：");
            }

            for (int j = 0; j < sampleCount; j++) {
                this.updateVehiclesStatus(vehicles, currTime, period);
                //this.broadcastHelloPacket(vehicles, helloCount);
                this.relaySelection(vehicles, helloCount);
                currTime += period;
            }

            StageResult sr = this.pathProcess(vehicles);
            //StageResult sr = this.pathProcessNew(vehicles);

            sumDelay += sr.getDelay() * sr.successCount;
            sumQuality += sr.getQuality() * sr.successCount;
            sumHops += sr.getHops() * sr.successCount;
            sumDist += sr.getDist() * sr.successCount;

            sumADelay += sr.getAdelay() * sr.totalCount;
            sumAQuality += sr.getAquality() * sr.totalCount;
            sumAHops += sr.getAhops() * sr.totalCount;
            sumADist += sr.getAdist() * sr.totalCount;

            sumCount += sr.totalCount;
            sumSuccess += sr.successCount;
            stageResult.addPathResultMap(sr.getPathResults());

            if (GeneralConfig.DEBUG_RESULT) {
                System.out.printf("Average Delay = %.3f\n", sr.getDelay());
                System.out.printf("Average Quality = %.3f\n", sr.getQuality());
                System.out.printf("Average Hops = %.3f\n", sr.getHops());
                System.out.printf("Total Count = %d\n", sr.totalCount);
                System.out.printf("Total Success = %d\n", sr.successCount);
                System.out.println("-----");
            }
        }

        stageResult.setParkSize(this.getParkVehiclesCount());
        stageResult.setMoveSize(this.getMoveVehiclesCount());
        stageResult.setDelay(sumDelay / sumSuccess);
        stageResult.setQuality(sumQuality / sumSuccess);
        stageResult.setHops(sumHops / sumSuccess);
        stageResult.setDist(sumDist / sumSuccess);
        stageResult.setAdelay(sumADelay / sumCount);
        stageResult.setAquality(sumAQuality / sumCount);
        stageResult.setAhops(sumAHops / sumCount);
        stageResult.setAdist(sumADist / sumCount);
        stageResult.totalCount = sumCount;
        stageResult.successCount = sumSuccess;

        return stageResult;
    }

    public StageResult simulationProcess(double period, int helloCount, int sampleCount, int processCount, boolean ov) {
        if (GeneralConfig.DEBUG_INFO) {
            System.out.println("[INFO]执行仿真处理过程...");
        }

        if (this.initf == false) {
            this.initSimulation(ov);
        }

        List<Vehicle> vehicles = new ArrayList<>();
        if (GeneralConfig.SIMULATION_TYPE == GeneralConfig.MOVE_ONLY) {
            vehicles.addAll(this.moveVehicleMap.values());
        } else {
            vehicles.addAll(this.moveVehicleMap.values());
            vehicles.addAll(this.parkVehicleMap.values());
        }

        System.out.println("Total Vehicle Count = " + vehicles.size());
        StageResult sr = this.doSimulation(vehicles, period, helloCount, sampleCount, processCount);

        if (GeneralConfig.DEBUG_HISTORY) {
            this.printAndSaveVirtualLinkHistory();
        }

        return sr;
    }

    public void printAndSaveVirtualLinkHistory() {
        for (VirtualLink vl : this.virtualLinkMap.values()) {
            System.out.println("VIRTUAL_LINK INFO = {");
            System.out.println("  Beg Vehicle = " + vl.getBegv().getId());
            System.out.println("  End Vehicle = " + vl.getEndv().getId());
            System.out.println("  Sheltered = " + vl.isSheltered());
            System.out.print("  LinkQuality History = [");
            for (Double d : vl.getLinkQualityHistory()) {
                System.out.printf("%.3f,", d);
            }
            System.out.printf("]\n  Distance = %.2fm\n", vl.getTransDistance());
            System.out.println("}");
        }
        System.out.println("VIRTUAL LINK SIZE = " + this.virtualLinkMap.size());
    }

    public static class PathResult {
        private Vehicle begv = null;
        private Vehicle endv = null;
        private Vehicle prev = null;
        private List<Vehicle> pathNodes = new ArrayList<>();
        private List<VirtualLink> pathLinks = new ArrayList<>();

        private boolean connected = true;
        private double quality = 0.0;
        private double delay = GeneralConfig.DOUBLE_MAX_VALUE;
        private double hops = GeneralConfig.DOUBLE_MAX_VALUE;
        private double dist = GeneralConfig.DOUBLE_MAX_VALUE;

        public PathResult(Vehicle b, Vehicle e) {
            this.begv = b;
            this.endv = e;
            this.dist = GeneralConfig.DOUBLE_MAX_VALUE;
        }

        public Vehicle getBegv() {
            return begv;
        }

        public void setBegv(Vehicle begv) {
            this.begv = begv;
        }

        public Vehicle getEndv() {
            return endv;
        }

        public void setEndv(Vehicle endv) {
            this.endv = endv;
        }

        public double getQuality() {
            return quality;
        }

        public void setQuality(double quality) {
            this.quality = quality;
        }

        public double getDelay() {
            return delay;
        }

        public void setDelay(double delay) {
            this.delay = delay;
        }

        public double getHops() {
            return hops;
        }

        public void setHops(double hops) {
            this.hops = hops;
        }

        public Vehicle getPrev() {
            return prev;
        }

        public void setPrev(Vehicle prev) {
            this.prev = prev;
        }

        public List<Vehicle> getPathNodes() {
            return pathNodes;
        }

        public void setPathNodes(List<Vehicle> pathNodes) {
            this.pathNodes = pathNodes;
        }

        public List<VirtualLink> getPathLinks() {
            return pathLinks;
        }

        public void setPathLinks(List<VirtualLink> pathLinks) {
            this.pathLinks = pathLinks;
        }

        public double getDist() {
            return dist;
        }

        public void setDist(double dist) {
            this.dist = dist;
        }

        public boolean isConnected() {
            return connected;
        }

        public void setConnected(boolean connected) {
            this.connected = connected;
        }

        @Override
        public String toString() {
            String str = new String();
            str += "[INFO] PATH RESULT INFO = {";
            str += "\n  Begin ID = " + this.begv.getId();
            str += "\n  End ID = " + this.endv.getId();
            str += "\n  Begin Pos = " + this.begv.getPosition();
            str += "\n  End Pos = " + this.endv.getPosition();
            str += "\n  Path NodeBase Count = " + this.pathNodes.size();
            str += "\n  Path DirectedLink Count = " + this.pathLinks.size();
            str += "\n  Distance = " + Utility.distance(this.begv.getPosition(), this.endv.getPosition());
            str += "\n  Delay = " + this.delay;
            str += "\n  Quality = " + this.quality;
            str += "\n}\n";

            return str;
        }
    }

    public static class StageResult {
        // 全部成功通信的通信参数
        private double delay = 0.0;
        private double quality = 0.0;
        private double hops = 0.0;
        private double dist = 0.0;

        // MOVE_ONLY和PARK_MOVE共同通信参数
        private double sdelay = 0.0;
        private double squality = 0.0;
        private double shops = 0.0;
        private double sdist = 0.0;

        // 含失败通信的通信参数
        private double adelay = 0.0;
        private double aquality = 0.0;
        private double ahops = 0.0;
        private double adist = 0.0;

        private int parkSize = 0;
        private int moveSize = 0;

        private Map<Integer, PathResult> pathResults = new HashMap<>();
        public int totalCount = 0;
        public int successCount = 0;

        public StageResult() { }

        public double getDelay() {
            return delay;
        }

        public void setDelay(double delay) {
            this.delay = delay;
        }

        public double getQuality() {
            return quality;
        }

        public void setQuality(double quality) {
            this.quality = quality;
        }

        public double getHops() {
            return hops;
        }

        public void setHops(double hops) {
            this.hops = hops;
        }

        public int getParkSize() {
            return parkSize;
        }

        public void setParkSize(int parkSize) {
            this.parkSize = parkSize;
        }

        public int getMoveSize() {
            return moveSize;
        }

        public void setMoveSize(int moveSize) {
            this.moveSize = moveSize;
        }

        public double getSdelay() {
            return sdelay;
        }

        public void setSdelay(double sdelay) {
            this.sdelay = sdelay;
        }

        public double getSquality() {
            return squality;
        }

        public void setSquality(double squality) {
            this.squality = squality;
        }

        public double getShops() {
            return shops;
        }

        public void setShops(double shops) {
            this.shops = shops;
        }

        public double getAdelay() {
            return adelay;
        }

        public void setAdelay(double adelay) {
            this.adelay = adelay;
        }

        public double getAquality() {
            return aquality;
        }

        public void setAquality(double aquality) {
            this.aquality = aquality;
        }

        public double getAhops() {
            return ahops;
        }

        public void setAhops(double ahops) {
            this.ahops = ahops;
        }

        public double getDist() {
            return dist;
        }

        public void setDist(double dist) {
            this.dist = dist;
        }

        public double getSdist() {
            return sdist;
        }

        public void setSdist(double sdist) {
            this.sdist = sdist;
        }

        public double getAdist() {
            return adist;
        }

        public void setAdist(double adist) {
            this.adist = adist;
        }

        public Map<Integer, PathResult> getPathResults() {
            return pathResults;
        }

        public void addPathResultMap(Map<Integer, PathResult> prs) {
            for (Integer key : prs.keySet()) {
                this.pathResults.put(key, prs.get(key));
            }
        }

        public void addPathResult(PathResult pr) {
            int key = pr.getBegv().getId() * 10000 + pr.getEndv().getId();
            this.pathResults.put(key, pr);
        }

        @Override
        public String toString() {
            NumberFormat nf = NumberFormat.getNumberInstance();
            nf.setMaximumFractionDigits(3);
            nf.setRoundingMode(RoundingMode.HALF_UP);

            String str = new String();
            str += "[INFO] STAGE RESULT INFO = {";
            str += "\n  Park Vehicle Size = " + this.parkSize;
            str += "\n  Move Vehicle Size = " + this.moveSize;
            str += "\n  Total Test Case = " + this.totalCount;
            str += "\n  Success Test Case = " + this.successCount;
            str += "\n  Average Delay = " + nf.format(this.delay);
            str += "\n  Average Quality = " + nf.format(this.quality);
            str += "\n  Average Hops = " + nf.format(this.hops);
            str += "\n  Average Dist = " + nf.format(this.dist);
            str += "\n  Average All Delay = " + nf.format(this.adelay);
            str += "\n  Average All Quality = " + nf.format(this.aquality);
            str += "\n  Average All Hops = " + nf.format(this.ahops);
            str += "\n  Average All Dist = " + nf.format(this.dist);
            str += "\n  Average Same Delay = " + nf.format(this.sdelay);
            str += "\n  Average Same Quality = " + nf.format(this.squality);
            str += "\n  Average Same Hops = " + nf.format(this.shops);
            str += "\n  Average Same Dist = " + nf.format(this.sdist);
            str += "\n}";
            return str;
        }
    }
}
